/* global Cesium */
// const Cartesian3 = Cesium.Cartesian3;
const Cartographic = Cesium.Cartographic;
const Ellipsoid = Cesium.Ellipsoid;
const Cartesian2 = Cesium.Cartesian2;
const SceneTransforms = Cesium.SceneTransforms;
const CesiumMath = Cesium.Math;
class GeoPoint {
    constructor(lon, lat, alt) {
        if (alt === undefined) {
            alt = 0;
        }
        this.lon = lon;
        this.lat = lat;
        this.alt = alt;
    }
    toJson() {
        return [this.lon, this.lat, this.alt];
    }
    static _transformLat = function(lng, lat) {
        let PI = 3.1415926535897932384626;
        let ret =
            -100.0 +
            2.0 * lng +
            3.0 * lat +
            0.2 * lat * lat +
            0.1 * lng * lat +
            0.2 * Math.sqrt(Math.abs(lng));
        ret += ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0) / 3.0;
        ret += ((20.0 * Math.sin(lat * PI) + 40.0 * Math.sin((lat / 3.0) * PI)) * 2.0) / 3.0;
        ret +=
            ((160.0 * Math.sin((lat / 12.0) * PI) + 320 * Math.sin((lat * PI) / 30.0)) * 2.0) / 3.0;
        return ret;
    };
    static _transformLng = function(lng, lat) {
        let PI = 3.1415926535897932384626;
        let ret =
            300.0 +
            lng +
            2.0 * lat +
            0.1 * lng * lng +
            0.1 * lng * lat +
            0.1 * Math.sqrt(Math.abs(lng));
        ret += ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0) / 3.0;
        ret += ((20.0 * Math.sin(lng * PI) + 40.0 * Math.sin((lng / 3.0) * PI)) * 2.0) / 3.0;
        ret +=
            ((150.0 * Math.sin((lng / 12.0) * PI) + 300.0 * Math.sin((lng / 30.0) * PI)) * 2.0) /
            3.0;
        return ret;
    };
    /**
     * Cartesian3坐标转GeoPoint（经纬度）坐标
     * @param Cart3Point
     * @return
     * ```
     * 示例代码：
     * let geoPoint =  GV.GeoPoint.fromCartesian3(newCartesian3(8065, 3650, 150000))
     * ```
     */
    static fromCartesian3 = function(Cart3Point) {
        let cartographic = Ellipsoid.WGS84.cartesianToCartographic(Cart3Point);
        let lat = CesiumMath.toDegrees(cartographic.latitude);
        let lon = CesiumMath.toDegrees(cartographic.longitude);
        let alt = cartographic.height;
        return new GeoPoint(lon, lat, alt);
    };
    /**
     * GeoPoint（经纬度）坐标转Cartesian3坐标
     * @param geoPoint
     * @return
     * ```
     * 示例代码：
     * let cart3 = GV.GeoPoint.toCartesian3({lon:80,lat:40,alt:50000})
     * ```
     */
    static toCartesian3 = function(geoPoint) {
        let cartographic = Cartographic.fromDegrees(geoPoint.lon, geoPoint.lat, geoPoint.alt);
        let cartesian3 = Ellipsoid.WGS84.cartographicToCartesian(cartographic);
        return cartesian3;
    };
    /**
     * 墨卡托坐标转GeoPoint（经纬度）坐标
     * @param x
     * @param y
     * @return
     * ```
     * 示例代码：
     * let geoPoint = GV.GeoPoint.fromMercator(8905559.263461886, 4865942.279503175)
     * ```
     */
    static fromMercator = function(x, y) {
        let lon = (x / 20037508.34) * 180;
        let lat = (y / 20037508.34) * 180;
        lat = (180 / Math.PI) * (2 * Math.atan(Math.exp((lat * Math.PI) / 180)) - Math.PI / 2);
        return new GeoPoint(lon, lat);
    };
    /**
     * GeoPoint（经纬度）坐标转墨卡托坐标
     * @param geoPoint
     * @return
     * ```
     * 示例代码：
     * let mct = GV.GeoPoint.toMercator({lon:80,lat:40,alt:50000})
     * ```
     */
    static toMercator = function(geoPoint) {
        let mercator = { x: 0, y: 0 };
        let earthRad = 6378137.0;
        mercator.x = ((geoPoint.lon * Math.PI) / 180) * earthRad;
        let a = (geoPoint.lat * Math.PI) / 180;
        mercator.y = (earthRad / 2) * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)));
        return mercator;
    };
    /**
     * 屏幕坐标转GeoPoint（经纬度）坐标（注：屏幕坐标范围必须在地球显示范围内）
     * @param x 屏幕x轴坐标
     * @param y 屏幕y轴坐标
     * @param viewer
     * @return
     * ```
     * 示例代码：
     * let mct = GV.GeoPoint.fromScreen(50,40,viewer)
     * ```
     */
    static fromScreen = function(x, y, viewer) {
        let pick1 = new Cartesian2(x, y);
        let cart;
        try {
            cart = viewer.scene.globe.pick(viewer.camera.getPickRay(pick1), viewer.scene);
            return this.fromCartesian3(cart);
        } catch (err) {
            console.log('fromScreen:输入的x，y值未在地球上找到相应经纬度值');
        }
    };
    /**
     * GeoPoint（经纬度）坐标转屏幕坐标
     * @param geoPoint
     * @param viewer
     * @return
     * ```
     * 示例代码：
     * let cart2 = GV.GeoPoint.toScreen({lon:8,lat:40,alt:5000},viewer)
     * ```
     */
    static toScreen = function(geoPoint, viewer) {
        let cartesian3 = GeoPoint.toCartesian3(geoPoint);
        return SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, cartesian3);
    };
    /**
     * 火星坐标转GeoPoint（经纬度）坐标
     * @param gcjPoint {x:y:}
     * @return
     */
    static fromGCJ02 = function(gcjPoint) {
        let PI = 3.1415926535897932384626;
        let a = 6378245.0;
        let ee = 0.00669342162296594323;
        let dLat = GeoPoint._transformLat(gcjPoint.x - 105.0, gcjPoint.y - 35.0);
        let dLng = GeoPoint._transformLng(gcjPoint.x - 105.0, gcjPoint.y - 35.0);
        let radLat = (gcjPoint.y / 180.0) * PI;
        let magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        let sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * PI);
        dLng = (dLng * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * PI);
        let mgLat = gcjPoint.y + dLat;
        let mgLng = gcjPoint.x + dLng;
        return new GeoPoint(gcjPoint.x * 2 - mgLng, gcjPoint.y * 2 - mgLat);
    };
    /**
     * GeoPoint（经纬度）坐标转火星坐标
     * @param geoPoint
     * @return
     * ```
     * 示例代码：
     * let gcj = GV.GeoPoint.toGCJ02({lon:8,lat:40,alt:5000});
     * ```
     */
    static toGCJ02 = function(geoPoint) {
        let PI = 3.1415926535897932384626;
        let a = 6378245.0;
        let ee = 0.00669342162296594323;
        let dLat = GeoPoint._transformLat(geoPoint.lon - 105.0, geoPoint.lat - 35.0);
        let dLng = GeoPoint._transformLng(geoPoint.lon - 105.0, geoPoint.lat - 35.0);
        let radLat = (geoPoint.lat / 180.0) * PI;
        let magic = Math.sin(radLat);
        magic = 1 - ee * magic * magic;
        let sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * PI);
        dLng = (dLng * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * PI);
        let mgLat = geoPoint.lat + dLat;
        let mgLng = geoPoint.lon + dLng;
        return { x: mgLng, y: mgLat };
    };
    /**
     * geoPoint转换成数组
     * @param geoPoint 点信息
     * @return
     * ```
     * 示例代码：
     * let res = GV.GeoPoint.pack({lon:8,lat:40,alt:5000})
     * ```
     */
    static pack = function(geoPoint) {
        let res = [];
        res.push(geoPoint.lon);
        res.push(geoPoint.lat);
        if (geoPoint.alt) {
            res.push(geoPoint.alt);
        }
        return res;
    };
    /**
     * 数组转换成geoPoint
     * @param arr 数组信息
     * @return
     * ```
     * 示例代码：
     * let res =  GV.GeoPoint.unpack([50,45,1555])
     * ```
     */
    static unpack = function(arr) {
        let geoPoint;
        let arrLen = arr.length;
        if (arrLen === 2) {
            for (let i = 0; i < arrLen - 1; i += 2) {
                geoPoint = new GeoPoint(arr[i], arr[i + 1]);
            }
        } else if (arrLen === 3) {
            for (let i = 0; i < arrLen - 2; i += 3) {
                geoPoint = new GeoPoint(arr[i], arr[i + 1], arr[i + 2]);
            }
        } else {
            console.warn('GeoPoint数据不规范');
        }
        return geoPoint;
    };
    /**
     * 批量geoPoint转换成数组
     * @param geoPoints 点数组信息
     * @return
     * ```
     * 示例代码：
     * let res = GV.GeoPoint.packArray([{lon:8,lat:40,alt:5000},{lon:45,lat:30,alt:55}])
     * ```
     */
    static packArray = function(geoPoints) {
        let _this = this;
        return geoPoints.map(function(item) {
            return _this.pack(item);
        });
    };
    /**
     * 批量数组转换成geoPoint
     * @param arr 数组信息
     * @return
     * ```
     * 示例代码：
     * let res =  GV.GeoPoint.unpackArray([[50,45,1555],[22,54,4545]])
     * ```
     */
    static unpackArray = function(arr) {
        let _this = this;
        return arr.map(function(item) {
            return _this.unpack(item);
        });
    };
    /**
     * 判断经纬坐标点是否相等
     * @param point1
     * @param point2
     */
    static isEqual = function(point1, point2) {
        if (point1 === point2) return true;
        if (!(point1 instanceof GeoPoint) || !(point2 instanceof GeoPoint)) return false;
        if (point1.lon !== point2.lon) return false;
        if (point1.lat !== point2.lat) return false;
        if (point1.alt !== point2.alt) return false;
        return true;
    };
    /**
     * 判断经纬坐标数组是否相等
     * @param arr1
     * @param arr2
     */
    static isEqualArr = function(arr1, arr2) {
        if (arr1 === arr2) return true;
        if (!(arr1 instanceof Array) || !(arr2 instanceof Array)) return false;
        if (arr1.length !== arr2.length) return false;
        for (let i = 0; i < arr1.length; i++) {
            if (!GeoPoint.isEqual(arr1[i], arr2[i])) return false;
        }
        return true;
    };
    /**
     * 深度复制
     */
    static clone = function(point, res) {
        if (res) {
            res.lon = point.lon;
            res.lat = point.lat;
            res.alt = point.alt;
            return res;
        }
        return new GeoPoint(point.lon, point.lat, point.alt);
    };
    /**
     * 度转度分秒
     * @param value
     */
    static _formatDegree = function(value) {
        value = Math.abs(value);
        let v1 = Math.floor(value); // 度
        let v2 = Math.floor((value - v1) * 60); // 分
        let v3 = Math.round(((value - v1) * 3600) % 60); // 秒
        return [v1, v2, v3];
    };
    /**
     * 度分秒转度数
     * @param value
     */
    static _degreeConvertBack = function(value) {
        let res = 0;
        res += value[0];
        res += value[1] / 60;
        res += value[2] / 3600;
        return res;
    };
    /**
     * 度转换度分秒
     * @param point
     */
    static formatDegree = function(point) {
        let res = new FormatGeoPoint();
        if (point.lon < 0) {
            res.lon.direction = 'west';
        } else {
            res.lon.direction = 'east';
        }
        let tempLon = GeoPoint._formatDegree(point.lon);
        res.lon.degrees = tempLon[0];
        res.lon.minutes = tempLon[1];
        res.lon.seconds = tempLon[2];
        if (point.lat < 0) {
            res.lat.direction = 'south';
        } else {
            res.lat.direction = 'north';
        }
        let tempLat = GeoPoint._formatDegree(point.lat);
        res.lat.degrees = tempLat[0];
        res.lat.minutes = tempLat[1];
        res.lat.seconds = tempLat[2];
        return res;
    };
    static degreeConvertBack = function(value) {
        let lon = GeoPoint._degreeConvertBack([
            value.lon.degrees,
            value.lon.minutes,
            value.lon.seconds,
        ]);
        if (value.lon.direction === 'west') lon = -lon;
        let lat = GeoPoint._degreeConvertBack([
            value.lat.degrees,
            value.lat.minutes,
            value.lat.seconds,
        ]);
        if (value.lat.direction === 'west') lat = -lat;
        return new GeoPoint(lon, lat);
    };
}

function FormatGeoPoint() {}
export default GeoPoint;
